── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.1.3 ✔ readr 2.1.4
✔ forcats 1.0.0 ✔ stringr 1.5.0
✔ ggplot2 3.4.3 ✔ tibble 3.2.1
✔ lubridate 1.9.3 ✔ tidyr 1.3.0
✔ purrr 1.0.2
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
Linking to GEOS 3.11.2, GDAL 3.6.2, PROJ 9.2.0; sf_use_s2() is TRUE
Loading on-brand Google fonts
Attaching package: 'scales'
The following object is masked from 'package:purrr':
discard
The following object is masked from 'package:readr':
col_factor
Attaching package: 'kableExtra'
The following object is masked from 'package:dplyr':
group_rows
Attaching package: 'zoo'
The following objects are masked from 'package:base':
as.Date, as.Date.numeric
Why do we care about zoning?







But zoning isn’t easy to understand





Zoning Atlases are here to help!





What’s a zoning atlas?
An interactive map that shows how local zoning district regulations impact certain types of housing.

How is it made?
- Following a methodology created by the National Zoning Atlas team.
- Reading, interpreting, understanding, communicating, mapping.
- Manually reading pages and pages of zoning ordinances.
- Translating local code into a standardized definition.
- Mapping zoning districts in GIS.
- REVIEW, REVIEW, REVIEW.

Goals of the zoning atlas
Standardize zoning information to show how jurisdictions are treating housing
Help make zoning more accessible for everyday people
Make comparisons across jurisdictions, and even state lines
Help implement and track zoning reforms
What does the atlas show us?
- Types of Zoning Districts
- Primarily Residential
- Mixed with Residential
- Nonresidential
- How are different types of housing treated?
- 1-Family
- 2-Family
- 3-Family
- 4+-Family
- Accessory Dwelling Units
What’s allowed by-right?
One of the most impactful features of the Atlas is the ability to show us how restrictive certain districts are.
- :thumbsup: Is it “Allowed/Conditional”?
- Meaning as long as it conforms to zoning and building requirements, all it takes is administrative approval.
- :ear: Does it require a “Public Hearing”?
- A public hearing process like a rezoning, special/conditional use permit, or a variance/special exception.
- :no_entry_sign: Prohibited
- It’s not allowed at all in the district.
Why does it matter?
The public approval process can be costly to both developers, residents, and communities.

- Additional time and uncertainty create risk.
- NIMBY opposition can lead to expensive concessions or simply end projects.
- Increased costs on developers get passed down to rent and purchase prices.
- Politicizes development in spite of community comprehensive plan goals.
Why should Hampton Roads care about zoning for housing?
Hampton Roads is not only getting older, it’s losing young people.
hr_age <- read_rds("../data/hr/hr_b25007.rds") |> # Load in saved data for age of householders in Hampton Roads.
mutate(age = case_when( # Create fewer age groupings.
age == "Householder 15 to 24 years" ~ "34 years or below",
age == "Householder 35 to 44 years" ~ "35 to 44 years",
age == "Householder 45 to 54 years" ~ "45 to 64 years",
age == "Householder 55 to 59 years" ~ "45 to 64 years",
age == "Householder 60 to 64 years" ~ "45 to 64 years",
TRUE ~ "65 years and over"
)) |>
group_by(year, age) |> # Group by age year and age.
summarise(estimate = sum(estimate)) |> # Aggregate.
filter(year == 2010 | year == 2021) |> # Filter for latest and earliest year.
pivot_wider(names_from = year, # Pivot to calculate the change.
values_from = estimate) |>
mutate(chg = `2021` - `2010`) # Caclulate the change from 2010 to 2021.
subtitle_text <- "<span style = 'color:#259591'><b>Senior households</b></span> have grown <b>significantly</b> from 2010 to 2021"
ggplot(hr_age,
aes(x = age,
y = chg,
fill = age)) +
geom_col() +
geom_text(aes(label = number_format(big.mark = ",",
style_positive = "plus",
style_negative = "minus")(chg),
hjust = ifelse(chg >= 0, 0, 1), color = age)) +
coord_flip() +
theme_hfv(base_size = 15) +
scale_fill_hfv() +
scale_color_hfv() +
labs(title = "Change in householders by age",
subtitle = subtitle_text,
caption = "**Source:** U.S. Census Bureau, ACS, 5-Year Estimates, Table B25007.") +
scale_y_continuous(labels = number_format(big.mark = ",", style_positive = "plus", style_negative = "minus"), limits = c(-10000, 70000), breaks = seq(-10000, 70000, by = 10000)) +
theme(panel.grid.major.y = element_line(color = "white"),
panel.grid.major.x = element_line(color = "#f5f5f5",size = 0.1)) +
plot_annotation(
theme = theme(
plot.subtitle = element_markdown(
margin = margin(b = 0.4, unit = 'cm'),
size = 11.5
)))Warning: The `size` argument of `element_line()` is deprecated as of ggplot2 3.4.0.
ℹ Please use the `linewidth` argument instead.

Smaller households are the norm.
# Create a visualization that shows the change in household size from 2010 to 2021 in each locality. Describe the trend in household size changes. Where are larger households seeing growth? Smaller households?
hr_hhsize <- read_rds("../data/hr/hr_hhsize.rds") |> # Read in household size data.
group_by(NAME, year, size) |> # Aggregate to locality, year, and household size.
summarise(estimate = sum(estimate)) |>
filter(year == 2010 | year == 2021) |> # Filter for latest and earliest years.
mutate(year = as.character(year)) |> # Convert year to a character.
pivot_wider(names_from = year,
values_from = estimate) |>
mutate(change = `2021` - `2010`) |> # Calculate the change from 2010 to 2021.
group_by(NAME) |> # Group by locality.
mutate(total_chg = sum(change)) |> # Calculate total change in order to order bar chart.
mutate(NAME = str_remove_all(NAME, " city")) # Remove " city" from all locality names.
subtitle_text <- "<span style = 'color:#011E41'><b>1-person</b></span> and <span style = 'color:#40C0C0'><b>2-person</span> households have grown the most from 2010 to 2021"
ggplot(hr_hhsize,
aes(x = reorder(NAME, total_chg),
y = change,
fill = size)) +
geom_col(position = "stack") +
theme_hfv(base_size = 15) +
coord_flip() +
facet_wrap(~size, nrow =1) +
scale_fill_hfv() +
labs(title = "Change in household size in Hampton Roads",
subtitle = subtitle_text,
caption = "**Source:** U.S. Census Bureau. ACS 5-Year Estimates. Table B25009.") +
add_zero_line(axis = "y") +
scale_y_continuous(labels = number_format(big.mark = ",", style_positive = "plus")) +
theme(panel.grid.major.y = element_line(color = "white"),
panel.grid.major.x = element_line(color = "#f5f5f5",size = 0.1)) +
plot_annotation(
theme = theme(
plot.subtitle = element_markdown(
margin = margin(b = 0.4, unit = 'cm'),
size = 11.5
)))
Hampton Roads isn’t building diverse housing.
# Create a visualization that shows where housing is being built. Where is more diverse housing being built? Where is single-family housing being built the most? How does that compare to population growth in those localities?
hr_bps <- read_rds("../data/hr/hr_bps.rds") |> # Load in Building Permits Survey data.
mutate(type = case_when( # Group "Missing Middle" housing together.
type == "2-units" ~ "2-4 units",
type == "3-4 units" ~ "2-4 units",
TRUE ~ type
)) |>
group_by(name_long, type) |> # Aggregate to locality and housing type.
summarise(units = sum(units)) |>
group_by(name_long) |> # Group by locality.
mutate(total = sum(units)) |> # Calculate the total number of new permits for entire time period.
mutate(name_long = str_remove(name_long, " City")) |> # Remove " City" from locality names.
mutate(name_long = case_when( # Add "City" back to James City County.
name_long == "James County" ~ "James City County",
TRUE ~ name_long
))
# Summarize the percentage of units developed by type for the narrative.
hr_bps_summary <- hr_bps |>
group_by(type) |> # Aggregate by housing type.
summarise(units = sum(units)) |>
mutate(pct = units/sum(units)) # Calculate the percentage of type of units for the region.
subtitle_text <- "Few, if any, <span style = 'color:#40C0C0'><b>2-4 unit housing</span> has been built between 2010 to 2022"
ggplot(hr_bps,
aes(x = reorder(name_long, total),
y = units,
fill = type)) +
geom_col(position = "stack") +
coord_flip() +
facet_wrap(~type) +
theme_hfv(base_size = 15) +
scale_fill_hfv() +
scale_y_continuous(labels = number_format(big.mark = ",", style_positive = "plus")) +
labs(title = "Total new residential building permits issued in Hampton Roads",
subtitle = subtitle_text,
caption = "**Source:** U.S. Census Bureau. Building Permits Survey.") +
theme(panel.grid.major.y = element_line(color = "white"),
panel.grid.major.x = element_line(color = "#f5f5f5",size = 0.1),
axis.text.x = element_text(angle = 90)) +
plot_annotation(
theme = theme(
plot.subtitle = element_markdown(
margin = margin(b = 0.4, unit = 'cm'),
size = 11.5
)))
Home prices have increased everywhere.
# What have home prices been like?
# How to add arrows indicating direction on line segments??
hr_var_price <- read_rds("../data/hr/hr_var.rds") |>
select(geography, period, name, adj_price) |>
mutate(year = substr(period, 1, 4)) |>
mutate(year = as.numeric(year)) |>
filter(period == "2023 Q2" | period == "2019 Q2") |>
mutate(period = as.character(period)) |>
select(geography, name, adj_price, period) |>
pivot_wider(names_from = period,
values_from = adj_price) |>
mutate(latest = `2023 Q2`) |>
pivot_longer(3:4,
names_to = "period",
values_to = "med_price") |>
mutate(name = case_when(
name == "Virginia Beach-Norfolk-Newport News MSA" ~ "VB-Norfolk-NN MSA",
TRUE ~ name
)) |>
mutate(name = str_remove(name, " City")) |>
mutate(name = case_when(
name == "James County" ~ "James City County",
TRUE ~ name
))
subtitle_text <- "In <span style = 'color:#011E41'><b>Q2 2019</b></span> and <span style = 'color:#40C0C0'><b>Q2 2023</span>"
ggplot(hr_var_price,
aes(x = reorder(name, latest),
y = med_price,
color = period)) +
theme_hfv(base_size = 15) +
geom_line(size = 1, color = "grey") +
geom_point() +
geom_text(data = subset(hr_var_price, name %in% c("James City County", "VB-Norfolk-NN MSA", "Portsmouth")),aes(label = dollar(med_price), hjust = ifelse(period == "2023 Q2", -0.25, 1.25))) +
coord_flip() +
labs(title = "Median home sales price in Hampton Roads",
subtitle = subtitle_text,
caption = "**Source:** Virginia REALTORS, adjusted to Q2 2023 dollars.") +
scale_y_continuous(labels = dollar_format(), limits = c(100000, 500000)) +
scale_color_hfv() +
plot_annotation(
theme = theme(
plot.subtitle = element_markdown(
margin = margin(b = 0.4, unit = 'cm'),
size = 11.5
))) +
theme(panel.grid.major.y = element_line(color = "white"),
panel.grid.major.x = element_line(color = "#dadada",size = 0.2))Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
ℹ Please use `linewidth` instead.

Average rent is approaching $1,400.
# What has rent been like in Hampton Roads?
hr_rent <- read_rds("../data/hr/hr_costar.rds") |>
select(period, rent, adj_price) |>
mutate(quarters = as.yearqtr(period)) |>
pivot_longer(2:3,
names_to = "rent",
values_to = "dollars")
subtitle_text <- "In <span style = 'color:#011E41'><b>Q2 2023 dollars</b></span> and <span style = 'color:#40C0C0'><b>current dollars</span>"
ggplot(hr_rent,
aes(x = quarters,
y = dollars,
color = rent,
linetype = rent)) +
geom_line() +
geom_point() +
theme_hfv(base_size = 15) +
scale_y_continuous(labels = dollar_format()) +
scale_x_yearqtr(breaks = seq(from = min(hr_rent$quarters),
to = max(hr_rent$quarters),
by = 1),format = '%Y-Q%q') +
theme(axis.text.x = element_text(angle = 90)) +
labs(title = "Average asking rent in Hampton Roads",
subtitle = subtitle_text,
caption = "**Source:** CoStar Group, Inc.") +
scale_color_hfv() +
plot_annotation(
theme = theme(
plot.subtitle = element_markdown(
margin = margin(b = 0.4, unit = 'cm'),
size = 11.5
))) +
theme(panel.grid.major.y = element_line(color = "#dadada", size = 0.1),
panel.grid.major.x = element_line(color = "#dadada",size = 0.1))
# scale_color_gradientn(colours = c("#ADDCB1", "#46A88F", "#207A88", "#0F1A4E"))The Top 5 Occupations would struggle to buy a home on their own.
hr_occ <- read_rds("../data/hr/hr_occ.rds") |>
select(occ_title, emp = tot_emp_2022, wage = a_median_2022, rent, ho_price) |>
mutate(`Total Employment` = label_number(big.mark = ",")(emp),
`Average Annual Wage` = dollar_format()(wage),
`Affordable Rent` = dollar_format()(rent),
`Affordable Home Price` = dollar_format()(ho_price)) |>
select(Industry = occ_title, `Total Employment`, `Average Annual Wage`, `Affordable Rent`, `Affordable Home Price`)
hr_occ_tbl <- hr_occ |>
kable(col.names = c(
"Industry",
"Total Employment",
"Annual Median Wage",
"Affordable Rent",
"Affordable Home Price"),
align = "lcccc"
) |>
kableExtra::kable_styling(
bootstrap_options = c("hover", "condensed", "responsive", "striped"), font_size = 30
)
hr_occ_tbl| Industry | Total Employment | Annual Median Wage | Affordable Rent | Affordable Home Price |
|---|---|---|---|---|
| Office and Administrative Support Occupations | 82,930 | $38,060 | $951.50 | $94,189 |
| Food Preparation and Serving Related Occupations | 69,100 | $27,240 | $681.00 | $56,921 |
| Sales and Related Occupations | 67,490 | $30,030 | $750.75 | $66,530 |
| Transportation and Material Moving Occupations | 61,100 | $36,940 | $923.50 | $90,331 |
| Business and Financial Operations Occupations | 53,260 | $75,320 | $1,883.00 | $222,526 |
The racial wealth gap is still wide in Hampton Roads.
hr_race_inc <- read_rds("../data/hr/hr_b19013.rds") |>
filter(year == 2021)
subtitle_text <- "In 2021, the wealth gap between <span style = 'color:#B1005F'><b>WHITE</b></span> and <span style = 'color:#40C0C0'><b>BLACK</span> households was <b>over $33,000 </b>"
ggplot(hr_race_inc,
aes(x = reorder(race, estimate),
y = estimate,
fill = race)) +
geom_col(position = "dodge") +
theme_hfv(base_size = 15) +
scale_fill_hfv() +
coord_flip() +
scale_y_continuous(labels = dollar_format(), expand = expansion(mult = c(0, 0.1))) +
theme(panel.grid.major.y = element_line(color = "white"),
panel.grid.major.x = element_line(color = "#f5f5f5",size = 0.1)) +
labs(title = "Median household income by race and ethnicity",
subtitle = subtitle_text,
caption = "**Source:** U.S. Census Bureau, ACS, 5-Year Estimates, Table B19013B-H.") +
plot_annotation(
theme = theme(
plot.subtitle = element_markdown(
margin = margin(b = 0.4, unit = 'cm'),
size = 11.5
)))
Why does this all matter to housing?
- Demand in the region has been changing. More and more households are aging, smaller, and renters.
- Supply is not providing a step between renting and owning.
- Average wages aren’t matching typical prices for housing.
- Income inequity and housing inequity are closely tied.
- More diverse housing options can support more diverse communities.
Zoning in Hampton Roads
Mixed with Residential zoning types make up only 3% of all developable land in the region.

Williamsburg has the largest proportion (22%) of Mixed with Residential zoning.
York County (14%) and Newport News (13%) follow.
hr_type <- read_rds("../data/hr/hr_vza_nogeo.rds") |>
select(jurisdiction, overlay, type, area) |>
filter(overlay == 0)
hr_type_summary <- hr_type |>
group_by(jurisdiction, type) |>
summarise(area = sum(area)) |>
group_by(jurisdiction) |>
mutate(percent = area/sum(area))
hr_summary <- hr_type |>
group_by(type) |>
summarise(area = sum(area)) |>
mutate(percent = area/sum(area))
ggplot(hr_type_summary,
aes(x = fct_reorder2(jurisdiction, type, percent),
y = percent,
fill = factor(type, levels = c("Nonresidential", "Mixed with Residential", "Primarily Residential")))) +
geom_col(position = "stack") +
coord_flip() +
theme_hfv(base_size = 15) +
scale_fill_hfv() +
labs(title = "Percent of land by type of zoning district",
caption = "**Source:** HousingForward Virginia, Virginia Zoning Atlas.") +
scale_y_continuous(labels = percent_format(), expand = expansion(mult = c(0, 0.01)))
69% of land in the region is dedicated to single-family detached only zoning.

Even more urban areas have a significant amount of land dedicated to single-family detached.
hr_sfd <- read_rds("../data/hr/hr_vza_nogeo.rds") |> # Read in the data.
select(jurisdiction, overlay, sfd, area) |> # Select necessary data fields.
filter(overlay == 0) |> # Remove overlay districts.
group_by(jurisdiction, sfd) |> # Sum the total acres dedicated to single-family detached in each district.
summarise(area = sum(area)) |>
group_by(jurisdiction) |>
mutate(percent = area/sum(area)) |>
ungroup() |>
mutate(total_hr = sum(area)) |> # Calculate what percentage of total developable area is SFD.
filter(sfd == "t")
ggplot(hr_sfd,
aes(x = reorder(jurisdiction, percent),
y = percent,
fill = percent)) +
geom_col(position = "dodge") +
geom_col_interactive(position = "dodge") +
geom_text(aes(label = percent(percent, 1), color = percent),
hjust = -0.2) +
theme_hfv(base_size = 15) +
coord_flip() +
scale_y_continuous(expand = expansion(mult = c(0, 0.1))) +
scale_fill_gradientn(colours = c("#ADDCB1", "#46A88F", "#207A88", "#0F1A4E")) + # Use custom HFV gradient.
scale_color_gradientn(colours = c("#ADDCB1", "#46A88F", "#207A88", "#0F1A4E")) + # Use custom HFV gradient.
labs(title = "Percent of developable land dedicated to single-family detached only",
caption = "**Source:** HousingForward Virginia, Virginia Zoning Atlas.") +
theme(axis.text.x = element_blank())
Newport News welcomes the most Missing Middle housing by-right.

But even in Newport News, the percentage is relatively low.
hr_byright <- read_rds("../data/hr/hr_vza_nogeo.rds") |>
select(jurisdiction, abbrvname, overlay, 6:9, area) |> # Select data fields.
filter(overlay == 0) |> # Filter out overlay districts.
group_by(jurisdiction) |>
mutate(total_area = sum(area)) |> # Calculate the total area of zoned land.
filter(family2_treatment == "allowed" & family3_treatment == "allowed" & family4_treatment == "allowed") |>
group_by(jurisdiction) |>
mutate(pct_2plus = area/total_area) |>
group_by(jurisdiction) |>
summarise(pct_2plus = sum(pct_2plus)) |>
add_row(jurisdiction = "Smithfield", pct_2plus = 0)
ggplot(hr_byright,
aes(x = reorder(jurisdiction, pct_2plus),
y = pct_2plus,
fill = pct_2plus)) +
geom_col() +
geom_text(aes(label = percent(pct_2plus, 1), color = pct_2plus),
hjust = -0.2) +
coord_flip() +
theme_hfv(base_size = 15) +
scale_fill_gradientn(colours = c("#ADDCB1", "#46A88F", "#207A88", "#0F1A4E")) + # Use custom HFV gradient.
scale_color_gradientn(colours = c("#ADDCB1", "#46A88F", "#207A88", "#0F1A4E")) + # Use custom HFV gradient.
scale_y_continuous(expand = expansion(mult = c(0, 0.1))) +
labs(title = "Percent of developable land allowing for 2+ family housing by-right",
caption = "**Source:** HousingForward Virginia, Virginia Zoning Atlas.") +
theme(axis.text.x = element_blank())
Norfolk welcomes the most 4+-family housing by-right.
hr_byright <- read_rds("../data/hr/hr_vza_nogeo.rds") |>
select(jurisdiction, abbrvname, overlay, 6:9, area) |> # Select data fields.
filter(overlay == 0) |> # Filter out overlay districts.
group_by(jurisdiction) |>
mutate(total_area = sum(area)) |> # Calculate the total area of zoned land.
filter(family4_treatment == "allowed") |>
group_by(jurisdiction) |>
mutate(pct_4plus = area/total_area) |>
group_by(jurisdiction) |>
summarise(pct_4plus = sum(pct_4plus))
ggplot(hr_byright,
aes(x = reorder(jurisdiction, pct_4plus),
y = pct_4plus,
fill = pct_4plus)) +
geom_col() +
geom_text(aes(label = percent(pct_4plus, 1), color = pct_4plus),
hjust = -0.2) +
coord_flip() +
theme_hfv() +
scale_fill_gradientn(colours = c("#ADDCB1", "#46A88F", "#207A88", "#0F1A4E")) + # Use custom HFV gradient.
scale_color_gradientn(colours = c("#ADDCB1", "#46A88F", "#207A88", "#0F1A4E")) + # Use custom HFV gradient.
scale_y_continuous(expand = expansion(mult = c(0, 0.1))) +
labs(caption = "**Source:** HousingForward Virginia, Virginia Zoning Atlas.")+
theme(axis.text.x = element_blank())
Accessory Dwelling Units (ADUs) are allowed by-right in many jurisdictions.
hr_adu <- read_rds("../data/hr/hr_vza_nogeo.rds") |>
select(type, jurisdiction, overlay, accessory_treatment, area) |>
filter(overlay == 0) |>
group_by(jurisdiction) |>
mutate(total_area = sum(area)) |>
filter(accessory_treatment == "allowed") |>
group_by(jurisdiction, type, total_area) |>
summarise(area = sum(area)) |>
mutate(pct = area/total_area) |>
ungroup() |>
filter(type == "Primarily Residential") |>
add_row(jurisdiction = "Surry (town)", total_area = 0, area = 0, pct = 0) |>
add_row(jurisdiction = "Newport News", total_area = 0, area = 0, pct = 0) |>
add_row(jurisdiction = "Chesapeake", total_area = 0, area = 0, pct = 0) |>
add_row(jurisdiction = "Windsor", total_area = 0, area = 0, pct = 0) |>
add_row(jurisdiction = "Smithfield", total_area = 0, area = 0, pct = 0) |>
add_row(jurisdiction = "Williamsburg", total_area = 0, area = 0, pct = 0)
ggplot(hr_adu,
aes(x = reorder(jurisdiction, pct),
y = pct,
fill = pct)) +
geom_col() +
geom_text(aes(label = percent(pct, accuracy = 0.1), color = pct, hjust = -0.2)) +
coord_flip() +
theme_hfv(base_size = 15) +
labs(caption = "**Source:** HousingForward Virginia, Virginia Zoning Atlas.") +
scale_y_continuous(labels = percent_format(), expand = expansion(mult = c(0, 0.1))) +
scale_fill_gradientn(colours = c("#ADDCB1", "#46A88F", "#207A88", "#0F1A4E")) + # Use custom HFV gradient.
scale_color_gradientn(colours = c("#ADDCB1", "#46A88F", "#207A88", "#0F1A4E")) + # Use custom HFV gradient.
theme(axis.text.x = element_blank())
But ADU regulations vary across the region and are often very prescriptive.
- Some jurisdictions outright prohibit rental of ADUs, some require that the ADU occupant is a family member, and some only allow for ADUs if it is attached to the primary house.
- Newport News and Chesapeake do not allow for ADUs at all.
More affordable housing is needed to support a diverse economy.
All areas of Hampton Roads have a shortage of affordable rentals to support low-wage jobs.
housing_needed <- read_rds("../data/hr/hr_blk_grps.rds") |>
filter(ratio > 2 | is.na(ratio))
pal <- colorFactor(palette =c("#8B85CA", "#40C0C0"),levels = c("R", "M"))
hr_byr4 <- read_rds("../data/hr/hr_byr4_map.rds")
fit_map <- hr_byr4 |>
addPolygons(data = housing_needed,
fillColor = "#66788d",
fillOpacity = 0.5,
color = "white",
weight = 1,
popup = paste0(
"Jurisdiction: ",
housing_needed$name_long,
"<br>",
"Ratio: ", housing_needed$label),
group = "Jobs-Housing Fit Ratio") |>
addLegend(data = housing_needed,
position = "topright",
colors = "#66788d",
labels = "Ratio > 2 or NA")Warning: sf layer has inconsistent datum (+proj=longlat +datum=NAD83 +no_defs).
Need '+proj=longlat +datum=WGS84'
fit_map |>
addProviderTiles(providers$CartoDB.Positron)Transit and multifamily housing
Public transit serves many areas that are already zoned by-right for 4+-Family Housing. But there are more opportunities for transit oriented development.
pal <- colorFactor(palette =c("#8B85CA", "#40C0C0"),levels = c("R", "M"))
transit_pal <-colorFactor(palette = c("#B1005F", "#E0592A", "#FFC658"), levels = c("WATA", "Hampton Roads Transit", "Suffolk Transit"))
hr_transit_map <- read_rds("../data/hr/hr_transit_map.rds")
hr_transit_map |>
addProviderTiles(providers$CartoDB.Positron)What now?
- Visit our Virginia Zoning Atlas page for full findings.
- Use the Virginia Zoning Atlas as a resource.
- Give us feedback on how we can expand this resource to support housing.
(https://housingforwardva.github.io/virginiazoningatlas/)
